package com.hyou.starter.autoconfigure.sc.endpoints.shutdown;

import java.util.Collections;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;

import com.netflix.discovery.DiscoveryClient;

/**
 * Spring Cloud的注册服务节点关闭，关闭服务时从服务注册中心移除注册信息
 * 
 * @author FengChangshuo
 * @version 1.0.0 2018-10-09 16:33:23 初始创建
 */
@Endpoint(id = "scshutdown", enableByDefault = false)
public class ShutdownEndpoint implements ApplicationContextAware {
    
    private static final Logger log = LoggerFactory.getLogger(ShutdownEndpoint.class);
    
    private static final String RES_KEY = "message";
    
    private static final Map<String, String> NO_CONTEXT_MESSAGE = Collections
            .unmodifiableMap(Collections.singletonMap(RES_KEY, "No context to shutdown."));
    
    private static final Map<String, String> SHUTDOWN_MESSAGE = Collections
            .unmodifiableMap(Collections.singletonMap(RES_KEY, "Shutting down, bye..."));
    
    private static final Map<String, String> SHUTDOWN_ERROR = Collections
            .unmodifiableMap(Collections.singletonMap(RES_KEY, "Error in shutting down client"));
    
    private ConfigurableApplicationContext context;
    
    @WriteOperation
    public Map<String, String> shutdown() {
        if (this.context == null) {
            return NO_CONTEXT_MESSAGE;
        }
        
        try {
            
            // 通知服务注册中心，注销当前服务节点
            context.getBean(DiscoveryClient.class).shutdown();
            return SHUTDOWN_MESSAGE;
        } catch (Exception th) {
            log.error("Error in shutting down client", th);
            return SHUTDOWN_ERROR;
        } finally {
            Thread thread = new Thread(this::performShutdown);
            thread.setContextClassLoader(getClass().getClassLoader());
            thread.start();
        }
    }
    
    private void performShutdown() {
        try {
            Thread.sleep(500L);
        } catch (InterruptedException ex) {
            log.error(ex.getMessage(), ex);
            Thread.currentThread().interrupt();
        }
        this.context.close();
    }
    
    @Override
    public void setApplicationContext(ApplicationContext context) {
        if (context instanceof ConfigurableApplicationContext) {
            this.context = (ConfigurableApplicationContext) context;
        }
    }
    
}
